
#include "head.h"
#include "sem.h"

int semid;

void clean(int sig)
{
    semctl(semid, 0, IPC_RMID);
    exit(0);
}

int main(int argc, char const *argv[])
{
    // 0，捕捉ctrl+c产生的SIGINT信号，使其正常删除SEM
    signal(SIGINT, clean);

    // 1，创建共享内存，并将SHM映射到本进程的内存空间
    key_t key1 = ftok(PROJPATH, PROJSHM);   
    int shmid = shmget(key1, 128, IPC_CREAT|0666);

    //    NULL: 让Linux自动为本SHM分配虚拟地址入口
    //    0   : 以读写方式映射
    char *p = shmat(shmid, NULL, 0);
    if(p == (void*)-1)
    {
        perror("shmat失败");
        exit(0);
    }

    // 2，创建信号量，并妥善处理初始化
    key_t key2 = ftok(PROJPATH, PROJSEM);   
    semid = semget(key2, 2, IPC_CREAT|IPC_EXCL|0666);
    if(semid != -1)
    {
        // 当前进程创建了该SEM，于是对其进行初始化
        sem_set(semid, DATA, 0); // 
        sem_set(semid, MEM , 1); // 
    }
    else if(semid == -1 && errno ==EEXIST)
    {
        // 信号量已存在，直接打开获取其ID
        semid = semget(key2, 2, IPC_CREAT|0666);
    }
    else
    {
        perror("semget() failed");
        exit(0);
    }

    // 3，让SHM放入数据
    while(1)
    {
        // 进入临界区前，申请获取资源（因为要写数据，申请内存MEM资源）
        // P操作：申请资源，使得sem减少
        if(!sem_p(semid, MEM))
            break;

        snprintf(p, 128, "%s", "abcdg\n");
        sleep(rand()%5+1);

        // 写完数据之后，释放（增加）数据资源
        sem_v(semid, DATA);
    }

    return 0;
}
